package cc.linker.steplink.crm.task;

import cc.linker.steplink.crm.commons.lock.RedisLock;
import cc.linker.steplink.crm.dao.RobotUserPortraitDao;
import cc.linker.steplink.crm.domain.*;
import cc.linker.steplink.crm.merchant.util.DateUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * @Description: 根据用户行为对用户标签进行进一步维护的伪智能机器人服务
 * @Author: wuhangfeng
 * @Date: Created in 2019/8/30 13:22
 * @Version: 1.8.3
 */
@Component
public class RobotUserPortraitTask {

    @Autowired
    private RobotUserPortraitDao robotUserPortraitDao;

    @Autowired
    private RedisTemplate redisTemplate;


    /**
     * @Description: 客户机器人用户画像
     * @Param: []
     * @Return: void
     * @Author: 锋
     * @Date: 2019/8/30 13:35
     * @Version:
     */
    @RedisLock(value = "ClientRobotUserPortraitTask")
    @Scheduled(cron = "0 0/10 * * * ?")
    public void clientRobotUserPortraitTask() {
        Map<String,Object> params = new HashMap<>(7);
        Date curDate = new Date();
        //客戶机器人
        String robotType = "client";
        params.put("robotkey","clientRobotSwitch");
        List<OrgRobotPo> robotPos = robotUserPortraitDao.getOrgRobots(params);
        //文章相关设置临时存储
        Map<String,Map<String,Object>> atricleSetMap = new HashMap<>();
        for (OrgRobotPo orgRobotPo:robotPos) {
            int adjustLabelNum=0;
            int adjustPushNum=0;
            params.put("startTime",DateUtil.dateStr(DateUtil.miniuteRoler(curDate,-10),"yyyy-MM-dd HH:mm:ss"));
            params.put("endTime",DateUtil.dateStr(curDate,"yyyy-MM-dd HH:mm:ss"));
            params.put("robotType",robotType);
            params.put("orgId",orgRobotPo.getOrgId());
            //获取客户机器人24小时前推送的记录
            List<ArticlePushRecord> pushRecords = robotUserPortraitDao.getArticlePushUserRecords(params);
            for (ArticlePushRecord pushRecord:pushRecords) {
                String articleId = pushRecord.getArticleId();
                String customerId = pushRecord.getCustomerId();
                Integer pushLevel = pushRecord.getPushLevel();
                params.put("customerId",customerId);
                params.put("articleId",articleId);
                params.put("pushLevel",pushLevel);
                CustomerLabelPo customerLabelPo = new CustomerLabelPo();
                customerLabelPo.setCustomerId(customerId);
                //查询用户阶段
                int stage = robotUserPortraitDao.getCustomerStage(params);
                //文章信息
                Map<String,Object> atricleInfo = atricleSetMap.get(articleId);
                if(atricleInfo == null){
                    atricleInfo = robotUserPortraitDao.getArticleInfo(params);
                }
                if(atricleInfo != null ){
                    atricleSetMap.put(articleId,atricleInfo);
                    //获取画像数据
                    ArticleCustomerDataPo dataPo = getArticleCustomerData(pushRecord);
                    //文章阅读时长
                    Integer articleReadTime = Integer.valueOf(atricleInfo.get("readTime").toString());
                    dataPo.setArticleReadTime(articleReadTime);
                    //获取文章标签
                    String labelPos = (String) atricleInfo.get("labelIds");
                    if(labelPos!=null){
                        for (String labelId:labelPos.split(",")) {
                            customerLabelPo.setLabelId(labelId);
                            //查询用户是否有标签
                            params.put("labelId", labelId);
                            Integer labelLevel = robotUserPortraitDao.getCustomerLabelLevel(params);
                            if(labelLevel!=null){
                                customerLabelPo.setLabelLevel(labelLevel);
                            }
                            if(stage == 1){
                                //第一阶段 设置标签及等级
                                adjustLabelNum = adjustLabelNum + setCustomerLabel(customerLabelPo,dataPo);
                            }else if(stage == 2){
                                //第二阶段 根据情况修改标签等级
                                adjustLabelNum = adjustLabelNum + changeCustomerLabelLevel(customerLabelPo,dataPo);
                            }
                        }
                    }
                    //调整用户推送频次
                    adjustPushNum = adjustPushNum + updateCutomerPushRate(params,dataPo);
                }
            }
            saveRobotAdjustInfo(orgRobotPo,adjustLabelNum,adjustPushNum,curDate);
        }
    }

    /**
     * @Description: 营销机器人用户画像
     * @Param: []
     * @Return: void
     * @Author: 锋
     * @Date: 2019/8/30 13:35
     * @Version:
     */
    @RedisLock(value = "MarketRobotUserPortraitTask")
    @Scheduled(cron = "0 0/10 * * * ?")
    public void marketRobotUserPortraitTask() {
        Map<String,Object> params = new HashMap<>(7);
        Date curDate = new Date();
        //营销机器人
        String robotType = "market";
        params.put("robotkey","marketRobotSwitch");
        List<OrgRobotPo> robotPos = robotUserPortraitDao.getOrgRobots(params);
        for (OrgRobotPo orgRobotPo:robotPos) {
            int adjustLabelNum=0;
            int adjustPushNum=0;
            params.put("startTime",DateUtil.dateStr(DateUtil.miniuteRoler(curDate,-10),"yyyy-MM-dd HH:mm:ss"));
            params.put("endTime",DateUtil.dateStr(curDate,"yyyy-MM-dd HH:mm:ss"));
            params.put("robotType",robotType);
            params.put("orgId",orgRobotPo.getOrgId());
            //获取营销机器人24小时前推送的记录
            List<ArticlePushRecord> pushRecords = robotUserPortraitDao.getArticlePushUserRecords(params);
            //文章相关设置临时存储
            Map<String,Map<String,Object>> atricleSetMap = new HashMap<>();
            for (ArticlePushRecord pushRecord:pushRecords) {
                String articleId = pushRecord.getArticleId();
                String customerId = pushRecord.getCustomerId();
                Integer pushLevel = pushRecord.getPushLevel();
                params.put("customerId",customerId);
                params.put("articleId",articleId);
                params.put("pushLevel",pushLevel);
                CustomerLabelPo customerLabelPo = new CustomerLabelPo();
                customerLabelPo.setCustomerId(customerId);
                //文章信息
                Map<String,Object> atricleInfo = atricleSetMap.get(articleId);
                if(atricleInfo == null){
                    atricleInfo = robotUserPortraitDao.getArticleInfo(params);
                }
                if(atricleInfo != null ) {
                    atricleSetMap.put(articleId,atricleInfo);
                    //获取画像数据
                    ArticleCustomerDataPo dataPo = getArticleCustomerData(pushRecord);
                    //文章阅读时长
                    Integer articleReadTime = Integer.valueOf(atricleInfo.get("readTime").toString());
                    dataPo.setArticleReadTime(articleReadTime);
                    //获取文章标签
                    String labelPos = (String) atricleInfo.get("labelIds");
                    if (labelPos != null) {
                        for (String labelId : labelPos.split(",")) {
                            customerLabelPo.setLabelId(labelId);
                            //查询用户是否有标签
                            params.put("labelId", labelId);
                            Integer labelLevel = robotUserPortraitDao.getCustomerLabelLevel(params);
                            if (labelLevel != null) {
                                //存在标签时根据情况修改标签等级
                                customerLabelPo.setLabelLevel(labelLevel);
                                adjustLabelNum = adjustLabelNum + changeCustomerLabelLevel(customerLabelPo, dataPo);
                            } else {
                                //不存在标签设置标签及等级
                                adjustLabelNum = adjustLabelNum + setCustomerLabel(customerLabelPo, dataPo);
                            }
                        }
                    }
                    //调整用户推送频次
                    adjustPushNum = adjustPushNum + updateCutomerPushRate(params, dataPo);
                }
            }
            saveRobotAdjustInfo(orgRobotPo,adjustLabelNum,adjustPushNum,curDate);
        }
    }

    /**
     * @Description: 用户活跃度调整
     * @Param: []
     * @Return: void
     * @Author: 锋
     * @Date: 2019/8/30 13:35
     * @Version:
     */
    @RedisLock(value = "userActiveTask")
    @Scheduled(cron = "0 59 23 * * ?")
    //@Scheduled(cron = "0 0/1 * * * ?")
    public void userActiveTask() {
        Map<String,Object> params = new HashMap<>(6);
        Date curDate = new Date();
        int activeNum = 0;
        //提升过活跃度的用户列表
        List<String> updateCustomer = new ArrayList<>();
        //获取所有启用的机器人的机构
        params.put("robotkey","ALL");
        List<OrgRobotPo> robotPos = robotUserPortraitDao.getAllOrgs(params);
        params.put("startTime",DateUtil.dateStr(DateUtil.dateRoler(curDate,-1),"yyyy-MM-dd HH:mm:ss"));
        params.put("endTime",DateUtil.dateStr(curDate,"yyyy-MM-dd HH:mm:ss"));
        for (OrgRobotPo orgRobotPo:robotPos) {
            params.put("orgId",orgRobotPo.getOrgId());
            List<Customer> customers = robotUserPortraitDao.getAllOrgCustomer(params);
            for (Customer customer:customers) {
                params.put("customerId",customer.getCustomerId());
                //获取用户旧等级
                Integer oldLevel = robotUserPortraitDao.getCustomerActiveLevel(params);
                Integer oneDayRecord = robotUserPortraitDao.getCustomerOneDayRecord(params);
                if(oneDayRecord>0) {//有行为
                    //一天内有行为，提升活跃度，且7天内必有行为，则不需要判断7天行为,且一天内只能提升一次
                    //oldLevel!=5 提升等级时如果已经是最高了就不修改了
                    if(!CustomerActiveLevel.LV5.equal(oldLevel) && !updateCustomer.contains(customer.getCustomerId())){
                        params.put("change",1);
                        robotUserPortraitDao.updateCustomerActive(params);
                        updateCustomer.add(customer.getCustomerId());
                        activeNum++;
                    }

                }else{
                    //一天内没有行为时判断7天
                    params.put("startTime",DateUtil.dateStr(DateUtil.dateRoler(curDate,-7),"yyyy-MM-dd HH:mm:ss"));
                    int sevenDayRecord = robotUserPortraitDao.getCustomerSevenDayRecord(params);
                    if(sevenDayRecord==0&&!CustomerActiveLevel.LV0.equal(oldLevel)){
                        //7天内没行为且不是最低级的时候可以降级
                        params.put("change",-1);
                        robotUserPortraitDao.updateCustomerActive(params);
                        activeNum++;
                    }
                }
            }
            if(activeNum!=0){
                Map<String,Object> record = new HashMap<>();
                record.put("orgId",orgRobotPo.getOrgId());
                record.put("robotType",orgRobotPo.getRobotType());
                record.put("adjustLabelNum",0);
                record.put("adjustPushNum",0);
                record.put("activeNum",activeNum);
                robotUserPortraitDao.insertRobotUserPortraitDetail(record);
            }
        }
    }

    private void saveRobotAdjustInfo(OrgRobotPo orgRobotPo,int adjustLabelNum,int adjustPushNum,Date dadjustDate){
        Map<String,Object> record = new HashMap<>();
        record.put("orgId",orgRobotPo.getOrgId());
        record.put("robotType",orgRobotPo.getRobotType());
        if(adjustLabelNum!=0||adjustPushNum!=0){
            record.put("adjustLabelNum",adjustLabelNum);
            record.put("adjustPushNum",adjustPushNum);
            record.put("activeNum",0);
            robotUserPortraitDao.insertRobotUserPortraitDetail(record);
        }
        if(adjustLabelNum!=0){
            //从redis获取当天调整总量
            String rediskey = "adjustLabelSum_"+orgRobotPo.getOrgId()+"_"+orgRobotPo.getRobotType()+"_"+DateUtil.dateStr(dadjustDate,"yyyy-MM-dd");
            Integer adjustLabelSum = (Integer) redisTemplate.opsForValue().get(rediskey);
            if(adjustLabelSum == null){
                adjustLabelSum = 0;
            }
            adjustLabelSum = adjustLabelSum+adjustLabelNum;
            redisTemplate.opsForValue().set(rediskey,adjustLabelSum,24*60, TimeUnit.MINUTES);
            record.put("dynamicType",2);
            record.put("dynamicContent","智能调整用户画像<span>"+adjustLabelSum+"</span>次");
            robotUserPortraitDao.insertRobotUserPortraitDynamic(record);
        }
    }

    /**
     * @Description: 获取用于用户画像的数据
     * @Param: [params]
     * @Return: cc.linker.steplink.crm.domain.ArticleCustomerDataPo
     * @Author: 锋
     * @Date: 2019/9/3 10:02
     * @Version: 1.8.3
     */
    private ArticleCustomerDataPo getArticleCustomerData(ArticlePushRecord pushRecord){
        Map<String,Object> params = new HashMap<>(5);
        params.put("articleId",pushRecord.getArticleId());
        params.put("customerId",pushRecord.getCustomerId());
        params.put("startTime",DateUtil.dateStr(pushRecord.getPushTime(),"yyyy-MM-dd HH:mm:ss"));
        params.put("endTime",DateUtil.dateStr(DateUtil.dateRoler(pushRecord.getPushTime(),1),"yyyy-MM-dd HH:mm:ss"));
        ArticleCustomerDataPo dataPo = new ArticleCustomerDataPo();
        //获取用户画像数据
        List<Map<String,Object>> datas = robotUserPortraitDao.getArticleCustomerData(params);
        for (Map<String,Object> data:datas) {
            if(data!=null){
                switch (Integer.valueOf(data.get("actionType").toString())) {
                    case 0:
                        //打开
                        dataPo.setOpenTag(Integer.valueOf(data.get("actionData").toString()));
                        break;
                    case 6:
                        //点赞
                        dataPo.setPraiseTag(Integer.valueOf(data.get("actionData").toString()));
                        break;
                    case 7:
                        //阅读时长
                        dataPo.setCustomerReadTime(Integer.valueOf(data.get("actionData").toString()));
                        break;
                    default:
                        break;
                }
            }
        }
        //是否打开
        /*int openTag = robotUserPortraitDao.getCustomerOpenTag(params);
        int praiseTag = 0;
        int customerReadTime = 0;
        if(openTag>1){
            //点赞标识
            praiseTag = robotUserPortraitDao.getCustomerPraiseTag(params);
            //用户阅读时长
            customerReadTime = robotUserPortraitDao.getCustomerReadTime(params);
        }
        dataPo.setPraiseTag(praiseTag);
        dataPo.setOpenTag(openTag);
        dataPo.setCustomerReadTime(customerReadTime);*/
        return dataPo;
    }

    /**
     * @Description: 修改用户标签等级
     * @Param: [customerLabelPo, labelId, openTag, praiseTag, customerReadTime, articleReadTime]
     * @Return: int 修改个数
     * @Author: 锋
     * @Date: 2019/9/3 9:43
     * @Version: 1.8.3
     */
    private int changeCustomerLabelLevel(CustomerLabelPo customerLabelPo,ArticleCustomerDataPo dataPo){
        Integer oldLabelLevel = customerLabelPo.getLabelLevel();
        //判断是否打开文章
        if(dataPo.getOpenTag()>0){
            //判断打开文章后是否点赞
            if(dataPo.getPraiseTag()>0){
                //点赞 等级+1
                if (!CustomerLabelLevel.LV3.equal(oldLabelLevel)){
                    //不是最高级时转化为+1等级
                    customerLabelPo.setLabelLevel(1);
                }else{
                    customerLabelPo.setLabelLevel(0);
                }
            }else{
                //未点赞时判断用户时长，对比文章预估时长 <0.5 等级-1 >=0.5&<=1.5 不变 >1.5 等级+1
                if(dataPo.getCustomerReadTime()<(0.5*dataPo.getArticleReadTime())&&!CustomerLabelLevel.LV1.equal(oldLabelLevel)){
                    customerLabelPo.setLabelLevel(-1);
                }else if(dataPo.getCustomerReadTime()>=(0.5*dataPo.getArticleReadTime())&&dataPo.getCustomerReadTime()<=(1.5*dataPo.getArticleReadTime())){
                    customerLabelPo.setLabelLevel(0);
                }else if(dataPo.getCustomerReadTime()>(1.5*dataPo.getArticleReadTime())&&!CustomerLabelLevel.LV3.equal(oldLabelLevel)){
                    customerLabelPo.setLabelLevel(1);
                }else{
                    customerLabelPo.setLabelLevel(0);
                }
            }
        }else {
            //未打开标签 等级-1
            if (!CustomerLabelLevel.LV1.equal(oldLabelLevel)){
                //不是最低级时转化为-1等级
                customerLabelPo.setLabelLevel(-1);
            }else{
                customerLabelPo.setLabelLevel(0);
            }
        }
        if(customerLabelPo.getLabelLevel()!=0){
            //等级有变化时
            robotUserPortraitDao.updateCustomerLabelLevel(customerLabelPo);
            return 1;
        }else{
            return 0;
        }
    }

    /**
     * @Description: 设置用户标签及等级
     * @Param: [customerLabelPo, labelId, openTag, praiseTag, customerReadTime, articleReadTime]
     * @Return: void
     * @Author: 锋
     * @Date: 2019/9/3 9:43
     * @Version: 1.8.3
     */
    private int setCustomerLabel(CustomerLabelPo customerLabelPo,ArticleCustomerDataPo dataPo){
        int openTag = dataPo.getOpenTag();
        int praiseTag = dataPo.getPraiseTag();
        int articleReadTime = dataPo.getArticleReadTime();
        int customerReadTime = dataPo.getCustomerReadTime();
        Integer oldLabelLevel = customerLabelPo.getLabelLevel();
        //判断是否打开文章
        if(openTag>0){
            //判断打开文章后是否点赞
            if(praiseTag>0){
                //点赞 强
                if(!CustomerLabelLevel.LV3.equal(oldLabelLevel)){
                    customerLabelPo.setLabelLevel(3);
                }
            }else{
                //未点赞时判断用户时长，对比文章预估时长 <0.5 弱. >=0.5&<=1.5 中 >1.5 强
                if(customerReadTime<(0.5*articleReadTime)&&!CustomerLabelLevel.LV1.equal(oldLabelLevel)){
                    customerLabelPo.setLabelLevel(1);
                }else if(customerReadTime>=(0.5*articleReadTime)&&customerReadTime<=(1.5*articleReadTime)&&!CustomerLabelLevel.LV2.equal(oldLabelLevel)){
                    customerLabelPo.setLabelLevel(2);
                }else if(customerReadTime>(1.5*articleReadTime)&&!CustomerLabelLevel.LV3.equal(oldLabelLevel)){
                    customerLabelPo.setLabelLevel(3);
                }
            }
            //等级发生变化时
            if(customerLabelPo.getLabelLevel()!=oldLabelLevel){
                robotUserPortraitDao.updateCustomerLabel(customerLabelPo);
                return 1;
            }else{
                return 0;
            }
        }else {
            //do nothing
            return 0;
        }
    }

    /**
     * @Description: 设置推送频次
     * @Param: [params]
     * @Return: void
     * @Author: 锋
     * @Date: 2019/9/3 9:31
     * @Version: 1.8.3
     */
    private int updateCutomerPushRate(Map<String,Object> params,ArticleCustomerDataPo dataPo){
        int openTag = dataPo.getOpenTag();
        int praiseTag = dataPo.getPraiseTag();
        int articleReadTime = dataPo.getArticleReadTime();
        int customerReadTime = dataPo.getCustomerReadTime();
        Integer pushLevel = (Integer) params.get("pushLevel");
        //推送频次变化标识
        int pushTag = 0;
        //判断是否打开文章
        if(openTag>0){
            //判断打开后是否点赞
            if(praiseTag>0){
                //点赞且不是最高级 推送等级升一级
                if(!CustomerPushRate.Two.equal(pushLevel)){
                    pushTag = 1;
                }
            }else{
                //未点赞时判断用户时长，对比文章预估时长 <0.5 降级. >=0.5&<=1.5 不变 >1.5 升级
                if(customerReadTime<(0.5*articleReadTime)&&!CustomerPushRate.Thirty.equal(pushLevel)){
                    pushTag = -1;
                }else if(customerReadTime>=(0.5*articleReadTime)&&customerReadTime<=(1.5*articleReadTime)){
                    pushTag = 0;
                }else if(customerReadTime>(1.5*articleReadTime)&&!CustomerPushRate.Two.equal(pushLevel)){
                    pushTag = 1;
                }
            }
        }else {
            //未打开文章，降级
            if(!CustomerPushRate.Thirty.equal(pushLevel)){
                pushTag = -1;
            }
        }
        params.put("pushTag",pushTag);
        //推送频次有变化时
        if(pushTag!=0){
            robotUserPortraitDao.updateCustomerPushRate(params);
            return 1;
        }else{
            return 0;
        }
    }

}
